#pragma once
#include <set>
#include <map>
#include "ElementsForGrammar.h"
#include <cstdarg>

using namespace std; 

#define oneP(lhs, ...)	{	_oneP(lhs, __VA_ARGS__, END_OF_RHS);  }


class Grammar{
private:
	vector<SYMBOL> terminals, nonterminals, vocabulary;
	vector<bool> marked_vocabulary;
	SYMBOL startSymbol;
	vector<Production> prods;
	map<SYMBOL, bool> derivesLambda;
	map<SYMBOL, set<SYMBOL> > firstSet;
	map<SYMBOL, set<SYMBOL> > followSet;
	vector< set<SYMBOL> > predictSet;
	map<SYMBOL, map<SYMBOL, vector<int> > > parseTable;
	//ParseTreeNode treeRoot;

	//method
	void initialization_terminals();
	void initialization_nonterminals();
	void initialization_vocabulary();
	void initialization_production();
	void initialization_testProduction();
	void initialization_testTerminals();
	void initialization_testNonterminals();
	void initialization_test2Production();
	void initialization_test2Terminals();
	void initialization_test2Nonterminals();

	void _oneP(SYMBOL lhs, ... ){
		vector<SYMBOL> p;							

		SYMBOL rhsSymbol = lhs;
		va_list ddd;  // dot dot dot

		va_start( ddd, lhs );     /* Initialize variable arguments. */
		while( rhsSymbol != END_OF_RHS )
		{
			rhsSymbol = va_arg( ddd, SYMBOL);
			p.push_back(rhsSymbol);
		}
		va_end( ddd );              /* Reset variable arguments.      */
		
		p.erase(p.end()-1);
		prods.push_back(Production(lhs,p));	
	}

	set<SYMBOL> computeFirst(vector<SYMBOL>& alpha);
	map<SYMBOL, bool>& markLambda(void);
	void fillFirstSet(void);
	void fillFollowSet(void);
	void fillPredictSet(void);
	void fillParseTable(void);
	
	

public:

	Grammar::Grammar();
	void printOutFirstSet();
	void printOutFollowSet();
	void printOutPredictSet();
	void printOutParseTable();
	void printOutConflictInParseTable();
	ParseTreeNode* constructParseTree(vector<SYMBOL> tokens);
	static void traverseTree(ParseTreeNode* root);
};

